/* Create a new page directory */
#include "include.h"

/* Data for finalising, after the async alloc operation */
typedef struct pdcreate_data {
    sos_pcb *pcb;
    page_table_cb cb;
    void *cb_data;
} pdcreate_data;

static void _pdcreate_frame_cb(seL4_Word vaddr, void *_data);

int sos_pager_create(sos_pcb *pcb, page_table_cb cb, void *cb_data) {
    int err;

    // Whack all finaliser data on the heap
    pdcreate_data *data = malloc(sizeof(struct pdcreate_data));
    if (data == NULL) {
        dprintf(6, "pager_create: could not allocate PD, OOM\n");
        return SOS_PAGE_TABLE_OOM;
    }

    // Stash PCB and other information
    data->pcb = pcb;
    data->cb = cb;
    data->cb_data = cb_data;

    // Sanity check - this must be invariant
    assert(sizeof(struct page_table_entry) == sizeof(seL4_Word));

    // Alloc a frame, assign it to PD
    err = frame_alloc(&_pdcreate_frame_cb, (void *) data);
    return err;
}

static void _pdcreate_frame_cb(seL4_Word vaddr, void *_data) {
    pdcreate_data *data = (pdcreate_data *) _data;
    dprintf(6, "pager_create: received PD frame %p\n", vaddr);
    if (vaddr == 0) {
        // SOS kernel is out of memory.
        // Pass the bad news to the calling component. RIP process.
        dprintf(6, "page_directory_create: kernel is OOM!\n");
        (*(data->cb))(SOS_PAGE_TABLE_OOM, data->cb_data);
    } else {
        // Successful frame_alloc
        data->pcb->sos_pd = vaddr;
        (*(data->cb))(SOS_PAGE_TABLE_SUCCESS, data->cb_data);
    }
    free(data);
}
